package com.gitee.srurl.system.config;

import com.gitee.srurl.core.annotation.ApiImpl;
import com.gitee.srurl.core.api.IDuplicateDetection;
import com.gitee.srurl.core.config.ShortUrlConfig;
import com.gitee.srurl.core.constant.ApiTypeConstant;
import com.gitee.srurl.core.constant.RedisConstant;
import com.gitee.srurl.core.exception.ServiceException;
import com.gitee.srurl.core.factory.ShortUrlFactory;
import com.gitee.srurl.core.util.SpringContextUtil;
import com.gitee.srurl.core.util.redis.RedisBloomUtil;
import com.gitee.srurl.core.event.bloom.ShortIdBloomSubscribeSupporter;
import com.gitee.srurl.core.event.bloom.ShortIdMd5BloomSubscribeSupporter;
import com.gitee.srurl.core.event.bloom.ShortIdMurmur5BloomSubscribeSupporter;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

/**
 * @author zxw
 * @date 2023/5/2 14:14
 */
@Slf4j
@Component
@DependsOn("shortUrlFactory")
public class BloomInitConfig {

    @PostConstruct
    private void init() {

        this.initBloomIfNoExists(RedisConstant.Bloom.SHORT_ID_BLOOM_BASE_KEY,
                Long.parseLong(SpringContextUtil.getRequiredProperty("short-url.bloom.short-id.expected-insertions")),
                Double.parseDouble(SpringContextUtil.getRequiredProperty("short-url.bloom.short-id.fpp"))
        );
        // 注册bloom事件
        ShortIdBloomSubscribeSupporter shortIdBloomSubscribeSupporter = new ShortIdBloomSubscribeSupporter();
        shortIdBloomSubscribeSupporter.register();

        ShortUrlConfig shortUrlConfig = ShortUrlFactory.getShortUrlConfig();
        IDuplicateDetection duplicateDetection = shortUrlConfig.getDuplicateDetection();
        ApiImpl annotation = duplicateDetection.getClass().getDeclaredAnnotation(ApiImpl.class);
        String value = annotation.value();
        switch (value) {
            case (ApiTypeConstant.DuplicateDetection.MD5):
                this.initBloomIfNoExists(RedisConstant.Bloom.BLOOM_DUPLICATE_MD5,
                        Long.parseLong(SpringContextUtil.getRequiredProperty("short-url.bloom.duplicate-md5.expected-insertions")),
                        Double.parseDouble(SpringContextUtil.getRequiredProperty("short-url.bloom.duplicate-md5.fpp"))
                );
                // 注册bloom事件
                ShortIdMd5BloomSubscribeSupporter shortIdMd5BloomSubscribeSupporter = new ShortIdMd5BloomSubscribeSupporter();
                shortIdMd5BloomSubscribeSupporter.register();
                break;
            case (ApiTypeConstant.DuplicateDetection.MURMUR_HASH):
                this.initBloomIfNoExists(RedisConstant.Bloom.BLOOM_DUPLICATE_MURMUR,
                        Long.parseLong(SpringContextUtil.getRequiredProperty("short-url.bloom.duplicate-murmur.expected-insertions")),
                        Double.parseDouble(SpringContextUtil.getRequiredProperty("short-url.bloom.duplicate-murmur.fpp"))
                );
                // 注册bloom事件
                ShortIdMurmur5BloomSubscribeSupporter shortIdMurmur5BloomSubscribeSupporter = new ShortIdMurmur5BloomSubscribeSupporter();
                shortIdMurmur5BloomSubscribeSupporter.register();
                break;
            case (ApiTypeConstant.DuplicateDetection.NO):
                break;
            default:
                log.error("DuplicateDetection bloom 未配置！");
                throw new ServiceException("过滤器未配置");
        }
    }

    /**
     * 初始化布隆过滤器(如果不存在)
     *
     * @param bloomKey           布隆过滤器key
     * @param expectedInsertions 预计数量
     * @param fpp                误差率
     */
    private void initBloomIfNoExists(String bloomKey, long expectedInsertions, double fpp) {
        boolean bloomExists = RedisBloomUtil.bloomExists(bloomKey);
        if (!bloomExists) {
            RedisBloomUtil.initBloom(bloomKey, expectedInsertions, fpp);
        }
    }
}
